import logging
import os
import time
from typing import Union

from .singleton import singleton

LOG_LEVELS = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]


@singleton
class LogManager:
	def __init__(self, save_log: bool = False, log_level = logging.INFO, log_folder: Union[None, str] = None,
				 logging_frequency = 1):
		self.name = "Logger"
		self.save_log = save_log
		self.log_level = logging.INFO if log_level not in LOG_LEVELS else log_level
		self.folder = os.getcwd() if log_folder is None else log_folder
		if not os.path.exists(os.path.join(self.folder, "log")):
			os.mkdir(os.path.join(self.folder, "log"))
		self.file = self._generate_log_filename()
		self.count = 0
		self.logging_frequency = logging_frequency

		self.logger = logging.getLogger()
		self.logger.setLevel(log_level)
		formatter = logging.Formatter(
			fmt = "%(asctime)s [%(levelname)s] %(name)s [%(count)d]: %(message)s",
			datefmt = "%Y-%m-%d %H:%M:%S",
		)

		if self.save_log:
			log_file_path = os.path.join(self.folder, "log", self.file)
			file_handler = logging.FileHandler(log_file_path, encoding = 'utf-8')
			file_handler.setFormatter(formatter)
			self.logger.addHandler(file_handler)

	def _generate_log_filename(self):
		return "{0}.log".format(time.strftime('%Y-%m-%d', time.localtime()))

	def update_filename(self):
		new_filename = self._generate_log_filename()
		if self.file != new_filename:
			self.file = new_filename
			for handler in self.logger.handlers:
				if isinstance(handler, logging.FileHandler):
					handler.baseFilename = os.path.join(self.folder, "log", self.file)

	def flush_log_file(self):
		if self.save_log:
			for handler in self.logger.handlers:
				if isinstance(handler, logging.FileHandler):
					handler.flush()

	def log(self, name: str, content: str, level = logging.INFO):
		self.count += 1
		self.log_level = logging.INFO if level not in LOG_LEVELS else level
		if self.save_log:
			self.update_filename()
			self.logger.log(level, "[%s]:%s", name, content, extra = {'count': self.count})
			if self.count % self.logging_frequency == 0:
				self.flush_log_file()
		print("{} [{}] [{}]: {}".format(time.strftime('%Y-%m-%d %H:%M:%S'), name, self.count, content))

	def clear_log(self, exception: Union[None, list] = None):
		exception = [] if exception is None else exception
		for filename in os.listdir(os.path.join(self.folder, "log")):
			if filename.endswith(".log") and filename not in exception:
				try:
					os.remove(os.path.join(self.folder, "log", filename))
				except PermissionError:
					self.count += 1
					print("{} [{}] [{}]: {}".format(time.strftime('%Y-%m-%d'), self.name, self.count,
													"{} 文件被占用，删除失败！".format(
														os.path.join(self.folder, 'log', filename))))

	def close(self):
		if self.count > 0 and self.save_log:
			self.log(self.name, "Logger is End\n")
			for handler in self.logger.handlers:
				handler.close()
			self.logger.handlers.clear()
			print("当前日志文件被保存在：{}".format(os.path.join(self.folder, 'log', self.file)))
